package com.arunsk.log4metrics.custom;

import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.apache.log4j.MDC;

import com.arunsk.log4metrics.level.Metrics;

public class MetricsLogger extends Logger {

	private static String FQCN = MetricsLogger.class.getName() + ".";

	private static TimeUnit unit;

	private static MetricsLoggerFactory metricsFactory = new MetricsLoggerFactory();

	protected MetricsLogger(String name) {
		super(name);
	}

	public static MetricsLogger getLogger(String name) {
		return getLogger(name, TimeUnit.SECONDS);
	}

	public static MetricsLogger getLogger(String name, TimeUnit timeUnit) {
		unit = timeUnit;
		return (MetricsLogger) Logger.getLogger(name, metricsFactory);
	}

	public void start() {

		if (Watcher.getInstance().isZero()) {
			put(String.valueOf(0));
			super.log(FQCN, Metrics.METRIC, "[Metrics Started]", null);
		}

		Watcher.getInstance().inc();
	}

	private void put(String key) {
		switch (unit) {

		case SECONDS:
			MDC.put(key, System.nanoTime() * 1E-9);
			break;
		case MILLISECONDS:
			MDC.put(key, System.nanoTime() * 1E-6);
			break;
		case MICROSECONDS:
			MDC.put(key, System.nanoTime() * 1E-3);
			break;
		case NANOSECONDS:
			MDC.put(key, System.nanoTime());
			break;
		case HOURS:
		case MINUTES:
		case DAYS:
		default:
			MDC.put(key, System.nanoTime() * 1E-9);
			break;

		}
	}

	public void stop() {

		double currentTime = System.nanoTime();
		double startTime = 0L;

		Watcher.getInstance().dec();
		
		if (Watcher.getInstance().isZero()) {
			startTime = Double.valueOf(get(String.valueOf(0)));

			super.log(FQCN, Metrics.METRIC, "Time elapsed is "
				+ getElapsedTime(startTime, currentTime) + "\n[Metrics Ended]",
				null);
		}
	}

	private String getElapsedTime(double startTime, double currentTime) {
		switch (unit) {

		case SECONDS:
			return (currentTime * 1E-9 - startTime) + " (s)"; 
		case MILLISECONDS:
			return (currentTime * 1E-6 - startTime) + " (ms)";
		case MICROSECONDS:
			return (currentTime * 1E-3 - startTime) + " (micros)";
		case NANOSECONDS:
			return (currentTime - startTime) + " (ns)";
		case HOURS:
		case MINUTES:
		case DAYS:
		default:
			return (currentTime * 1E-9 - startTime) + " (s)";
		}
	}

	private String get(String key) {
		return String.valueOf(MDC.get(key));
	}
}
